/*
 * ReferenceCountingPointer.h
 *
 *  Created on: 20/nov/2010
 *      Author: computer
 */

#ifndef REFERENCECOUNTINGPOINTER_H_
#define REFERENCECOUNTINGPOINTER_H_

template <class T> class ReferenceCountingPointer {
public:
	explicit ReferenceCountingPointer(T* p = 0) {
		if (p) data = new Data(p);
		else data = 0;
	}
	ReferenceCountingPointer(const ReferenceCountingPointer& snd) {
		acquire(snd.data);
	}

	//Pointer() : data(NULL) { }

	ReferenceCountingPointer& operator=(const ReferenceCountingPointer& r) {
		if (this != &r) {
			release();
			acquire(r.data);
		}
		return *this;
	}

	~ReferenceCountingPointer() {
		release();
	}

	T* operator->() const {
		return data->ptr;
	}

	T& operator*() const {
		return *data->ptr;
	}

	/*void set(T* p) {
		if (data) {
			delete data->prt;
			data->ptr = p;
		}
		else {
			data = new Data(p);
		}
	}*/

	T* get() const { return data ? data->ptr : 0; }

	bool isNull() { return data ? data->ptr == 0 : true; }

private:
	struct Data {
		Data(T* p = 0, unsigned int _counter = 1) : ptr(p), counter(_counter) { }
		T* ptr;
		unsigned int counter;
	}* data;

	void acquire(Data* c) {
		data = c;
		if (c) ++c->counter;
	}

	void release() {
		if (data) {
			if (--data->counter == 0) {
				delete data->ptr;
				delete data;
			}
			data = 0;//TODO why here?
		}
	}
};

#endif /* REFERENCECOUNTINGPOINTER_H_ */
